Wykres prezentuje ilościowy rozkład zawartości galerii, pogrupowany według typu mediów oraz ich sumarycznej liczebności. Wewnętrzne podziały kolorystyczne słupków identyfikują techniczne źródło każdego pliku, wskazując na konkretny obiektyw (np. szeroki kąt, selfie) lub pochodzenie systemowe (np. zrzut ekranu).
kolory_pochodzenia <- c(
"Aparat Główny" = "#4E79A7",
"Selfie (Przód)" = "#F28E2B",
"Szeroki Kąt" = "#59A14F",
"Zoom (Tele)" = "#EDC948",
"Aplikacje / Inne" = "#BAB0AC",
"Vlog (Przód)" = "#E15759",
"Wideo (Tył)" = "#76B7B2"
)
przygotuj_dane <- function(nazwa_pliku, imie_osoby) {
nazwy_kolumn <- c("Data", "Typ_Live", "Album", "Typ", "CzyUlubione",
"CzyScreenshot", "Rozmiar", "Obiektyw")
if (!file.exists(nazwa_pliku)) return(NULL)
read.csv(nazwa_pliku, sep = ";", header = FALSE, col.names = nazwy_kolumn,
stringsAsFactors = FALSE, fill = TRUE) %>%
mutate(
Obiektyw = str_to_lower(str_trim(Obiektyw)),
Typ = str_trim(Typ),
CzyScreenshot = str_trim(CzyScreenshot),
Typ_Live = str_trim(Typ_Live),
Kategoria = case_when(
CzyScreenshot %in% c("Tak", "Yes", "True", "1") ~ "Zrzuty Ekranu",
Typ == "Wideo" ~ "Wideo",
str_detect(Typ_Live, "Live") ~ "Live Photos",
TRUE ~ "Zdjęcia Statyczne"
),
Pochodzenie = case_when(
Kategoria == "Zrzuty Ekranu" ~ "Aplikacje / Inne",
str_detect(Obiektyw, "front") & Kategoria == "Wideo" ~ "Vlog (Przód)",
str_detect(Obiektyw, "front") ~ "Selfie (Przód)",
str_detect(Obiektyw, "ultra wide") ~ "Szeroki Kąt",
str_detect(Obiektyw, "telephoto") ~ "Zoom (Tele)",
Kategoria == "Wideo" ~ "Wideo (Tył)",
TRUE ~ "Aparat Główny"
)
) %>%
group_by(Kategoria, Pochodzenie) %>%
summarise(Liczba = n(), .groups = 'drop') %>%
mutate(Osoba = imie_osoby)
}
d1 <- przygotuj_dane("leozdj.txt", "Leonard")
d2 <- przygotuj_dane("pablo_fotki.txt", "Paweł")
d3 <- przygotuj_dane("WojciechoweFotografie.txt", "Wojciech")
dane_full <- bind_rows(d1, d2, d3)
sd <- SharedData$new(dane_full)
wykres <- plot_ly(sd, x = ~Kategoria, y = ~Liczba, type = 'bar',
color = ~Pochodzenie,
colors = kolory_pochodzenia,
hovertemplate = paste(
"<b>%{data.name}</b><br>",
"Liczba: <b>%{y}</b><extra></extra>"
)
) %>%
layout(
barmode = 'stack',
bargap = 0.3,
xaxis = list(title = list(text = "Typ Mediów"), tickfont = list(size = 12), showgrid = FALSE),
yaxis = list(title = list(text = "Ilość Zdjęć"), gridcolor = "#eee", zeroline = FALSE),
legend = list(title = list(text = "<b>Obiektyw / Źródło</b>"), bgcolor = "rgba(255,255,255,0.5)"),
paper_bgcolor = "white",
plot_bgcolor = "white",
font = list(family = "Verdana", color = "#333")
)
css_buttons <- "
.crosstalk-input-checkboxgroup .crosstalk-options-group {
display: flex;
justify-content: center;
gap: 15px;
flex-wrap: wrap;
}
.crosstalk-input-checkboxgroup input[type='checkbox'] {
display: none;
}
.crosstalk-input-checkboxgroup span {
display: inline-block;
padding: 10px 30px;
background-color: #f5f5f5;
color: #666;
border: 1px solid #ddd;
border-radius: 50px;
font-family: 'Verdana', sans-serif;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
user-select: none;
}
.crosstalk-input-checkboxgroup span:hover {
background-color: #e0e0e0;
}
.crosstalk-input-checkboxgroup input[type='checkbox']:checked + span {
background-color: #4E79A7; /
color: white;
border-color: #4E79A7;
box-shadow: 0 4px 10px rgba(78, 121, 167, 0.4);
transform: translateY(-2px);
}
"
bscols(
widths = 12,
list(
div(
tags$style(HTML(css_buttons)),
style = "max-width: 900px; margin: 0 auto; padding: 20px; font-family: 'Verdana', sans-serif;",
div(
style = "text-align: center; margin-bottom: 25px;",
h3("Panel Kontrolny", style = "color: #333; margin-bottom: 5px;"),
p("Kliknij przycisk, aby włączyć/wyłączyć dane osoby:", style = "color: #888; font-size: 14px; margin-bottom: 20px;"),
filter_checkbox("filtr_osoby", "", sd, ~Osoba, inline = TRUE)
)
),
div(
style = "max-width: 1000px; margin: 0 auto; box-shadow: 0 4px 20px rgba(0,0,0,0.08); border-radius: 12px; overflow: hidden; border: 1px solid #f0f0f0;",
wykres
)
)
)
Kliknij przycisk, aby włączyć/wyłączyć dane osoby:
normalize_date <- function(x) {
x <- str_trim(x)
x <- str_replace_all(x, "\\s+", " ")
x <- str_replace_all(x, " o ", " ")
x <- str_replace_all(x, " at ", " ")
x <- str_replace_all(x, "\\.", "")
map_mies <- c(
"sty"="Jan","lut"="Feb","mar"="Mar","kwi"="Apr","maj"="May","cze"="Jun",
"lip"="Jul","sie"="Aug","wrz"="Sep","paź"="Oct","paz"="Oct","lis"="Nov","gru"="Dec"
)
for (pl in names(map_mies)) {
x <- str_replace_all(x, paste0("\\b", pl, "\\b"), map_mies[[pl]])
}
x <- str_replace_all(x, "\\s+", " ")
x
}
parse_gallery_datetime <- function(x) {
x2 <- normalize_date(x)
parse_date_time(
x2,
orders = c(
"d b Y H:M", "d B Y H:M",
"d b Y H:M:S", "d B Y H:M:S"
),
tz = "UTC"
)
}
wczytaj_surowe_czas <- function(nazwa_pliku, imie_osoby) {
nazwy_kolumn <- c("Data", "Typ_Live", "Album", "Typ", "CzyUlubione",
"CzyScreenshot", "Rozmiar", "Obiektyw")
if (!file.exists(nazwa_pliku)) return(NULL)
read.csv(
nazwa_pliku, sep=";", header=FALSE, col.names=nazwy_kolumn,
stringsAsFactors=FALSE, fill=TRUE
) %>%
mutate(
Osoba = imie_osoby,
dt = parse_gallery_datetime(Data)
) %>%
filter(!is.na(dt))
}
raw1 <- wczytaj_surowe_czas("leozdj.txt", "Leonard")
raw2 <- wczytaj_surowe_czas("pablo_fotki.txt", "Paweł")
raw3 <- wczytaj_surowe_czas("WojciechoweFotografie.txt", "Wojciech")
dane_czas <- bind_rows(raw1, raw2, raw3) %>%
mutate(
Miesiac = factor(
month(dt), # 1..12
levels = 1:12,
labels = c("sty","lut","mar","kwi","maj","cze","lip","sie","wrz","paź","lis","gru")
),
DzienTyg = {
wd <- wday(dt, week_start = 1)
etyk <- c("Pon","Wt","Śr","Czw","Pt","Sob","Nd")
factor(etyk[wd], levels = etyk)
},
Godzina = factor(sprintf("%02d", hour(dt)), levels = sprintf("%02d", 0:23))
)
sd_czas <- SharedData$new(dane_czas, group = "czas")
Wykres przedstawie ilość zdjęć wykonanych przez wybraną osobę/osoby w podziale na trzy okresy czasu, godziny, dni oraz miesiące
df_m <- dane_czas %>% count(Osoba, Miesiac, name = "Liczba")
df_d <- dane_czas %>% count(Osoba, DzienTyg, name = "Liczba")
df_g <- dane_czas %>% count(Osoba, Godzina, name = "Liczba")
sd_m <- SharedData$new(df_m, key = ~Osoba, group = "czas")
sd_d <- SharedData$new(df_d, key = ~Osoba, group = "czas")
sd_g <- SharedData$new(df_g, key = ~Osoba, group = "czas")
filtr <- div(
style = "max-width: 1000px; margin: 0 auto; padding: 10px 0; text-align:center;",
p("Wybierz osoby:", style="color:#888; font-size:14px; margin-bottom:10px;"),
filter_checkbox("filtr_osoby_czas", "", sd_m, ~Osoba, inline = TRUE)
)
fig_m <- plot_ly(sd_m, x = ~Miesiac, y = ~Liczba, type = "bar", color = ~Osoba) %>%
layout(
barmode = "group",
xaxis = list(title = list(text = "Miesiąc")),
yaxis = list(title = list(text = "Liczba zdjęć"))
)
fig_d <- plot_ly(sd_d, x = ~DzienTyg, y = ~Liczba, type = "bar", color = ~Osoba) %>%
layout(
barmode = "group",
xaxis = list(title = list(text = "Dzień tygodnia")),
yaxis = list(title = list(text = "Liczba zdjęć"))
)
fig_g <- plot_ly(sd_g, x = ~Godzina, y = ~Liczba, type = "bar", color = ~Osoba) %>%
layout(
barmode = "group",
xaxis = list(title = list(text = "Godzina (00–23)")),
yaxis = list(title = list(text = "Liczba zdjęć"))
)
#dropdown
selector <- div(
style="max-width:1000px; margin: 0 auto; padding: 0 0 10px 0;",
tags$label("Tryb:", `for`="tryb_czas", style="margin-right:8px; color:#666; font-weight:600;"),
tags$select(
id="tryb_czas",
style="padding:6px 10px; border-radius:6px; border:1px solid #ccc;",
tags$option(value="m", "Miesiące"),
tags$option(value="d", "Dni tygodnia"),
tags$option(value="g", "Godziny")
)
)
#sterowanie wykresami
js <- "
document.addEventListener('DOMContentLoaded', function () {
const sel = document.getElementById('tryb_czas');
const pm = document.getElementById('plot_m');
const pd = document.getElementById('plot_d');
const pg = document.getElementById('plot_g');
function show(v){
pm.style.display = (v === 'm') ? 'block' : 'none';
pd.style.display = (v === 'd') ? 'block' : 'none';
pg.style.display = (v === 'g') ? 'block' : 'none';
}
sel.addEventListener('change', function(){ show(sel.value); });
show(sel.value);
});
"
panel_style <- "max-width: 1000px; margin: 0 auto; box-shadow: 0 4px 20px rgba(0,0,0,0.08); border-radius: 12px; overflow:hidden; border: 1px solid #f0f0f0;"
div(
filtr,
selector,
tags$script(HTML(js)),
div(style=panel_style,
div(id="plot_m", fig_m),
div(id="plot_d", style="display:none;", fig_d),
div(id="plot_g", style="display:none;", fig_g)
)
)
Wybierz osoby:
Poniższa interaktywna mapa przedstawia lokalizacje wykonania naszych zdjęć. Mamy też opcję wyboru miesięcy, w celu zobaczenia gdzie i ile zdjęć wykonanych było w tym właśnie miesiącu / miesiącach. Dodatkowo mamy możliwość wyboru stylu mapy, zgodnie z preferencjami odbiorcy.